import time
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.svm import SVC

## 设置属性防止中文乱码
mpl.rcParams['font.sans-serif']=[u'simHei']
mpl.rcParams['axes.unicode_minus']=False

def run():
    ## 读取数据
    # 'sepal length', 'sepal width', 'petal length', 'petal width'
    iris_feature = u'花萼长度', u'花萼宽度', u'花瓣长度', u'花瓣宽度'
    path='../data/iris.data'  # 数据文件路径
    data=pd.read_csv(path,header=None)
    x,y=data[list(range(4))],data[4]
    y=pd.Categorical(y).codes
    x=x[[0,1]]
    ## 数据分割
    x_train,x_test,y_train,y_test=train_test_split(x,y,train_size=0.6,random_state=0)

    Cs=[0.1,1,10,100,500,10000]
    svcs = []
    t_score = []
    y_score1 = []
    y_score2 = []
    ## 数据SVM分类器构建
    for i,c in enumerate(Cs):
        svc=SVC(C=c,kernel='rbf')
        # C越大，泛化能力越差，会出现过拟合的问题
        # C越小，泛化能力越好，但是容易出现欠拟合的问题
        ## 模型训练
        t0=time.time()
        svc.fit(x_train,y_train)
        t=time.time()-t0
        t_score.append(t)
        svcs.append(svc)
        ### 效果评估
        svm_score1=accuracy_score(y_train,svc.predict(x_train))
        svm_score2=accuracy_score(y_test,svc.predict(x_test))
        y_score1.append(svm_score1)
        y_score2.append(svm_score2)

    ## 画图
    x_tmp=[0,1,2,3,4,5]
    plt.figure(facecolor='w',figsize=(12,6))

    plt.subplot(121)
    plt.plot(x_tmp,y_score1,'r-',lw=2,label=u'训练集准确率')
    plt.plot(x_tmp,y_score2,'g-',lw=2,label=u'测试集准确率')
    plt.xlim(-0.3,3.3)
    plt.ylim(np.min((np.min(y_score1),np.min(y_score2)))*0.9,np.max((np.max(y_score1),np.max(y_score2)))*1.1)
    plt.legend(loc='lower left')
    plt.title(u'模型预测准确率',fontsize=13)
    plt.xticks(x_tmp,[u'C=0.1', u'C=1', u'C=10', u'C=100', u'C=500', u'C=10000'],rotation=0)
    plt.grid(b=True)

    plt.subplot(122)
    plt.plot(x_tmp,t_score,'b-',lw=2,label=u'模型训练时间')
    plt.title(u'模型训练耗时',fontsize=13)
    plt.xticks(x_tmp,[u'C=0.1', u'C=1', u'C=10', u'C=100', u'C=500', u'C=10000'],rotation=0)
    plt.grid(b=True)

    plt.suptitle(u'鸢尾花数据SVM分类器不同内核函数模型比较',fontsize=16)
    plt.show()
    ### 预测结果画图
    ### 画图比较
    N=500
    x1_min,x2_min=x.min()
    x1_max,x2_max=x.max()

    t1=np.linspace(x1_min,x1_max,N)
    t2=np.linspace(x2_min,x2_max,N)
    x1,x2=np.meshgrid(t1,t2) # 生成网格采样点
    grid_show=np.dstack((x1.flat,x2.flat))[0] # 测试点

    ## 画图
    cm_light=mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark=mpl.colors.ListedColormap(['g', 'r', 'b'])
    plt.figure(facecolor='w',figsize=(14,7))

    for i in range(6):
        ## 获取各个不同算法的测试值
        svm_grid_predict=svcs[i].predict(grid_show)
        svm_grid_predict=svm_grid_predict.reshape(x1.shape) # 使之与输入的形状相同
        ### svm
        plt.subplot(231+i)
        ## 区域图
        plt.pcolormesh(x1, x2, svm_grid_predict, cmap=cm_light)
        ## 所以样本点
        plt.scatter(x[0],x[1],c=y,edgecolors='k',s=50,cmap=cm_dark) # 样本
        ## 测试数据集
        plt.scatter(x_test[0],x_test[1],s=120,facecolors='none',zorder=10) # 圈中测试集样本
        ## lable列表
        plt.xlabel(iris_feature[0],fontsize=13)
        plt.ylabel(iris_feature[1],fontsize=13)
        plt.xlim(x1_min,x1_max)
        plt.ylim(x2_min,x2_max)
        plt.title(u'C=%s' %(Cs[i]),fontsize=15)
        plt.grid(b=True,ls=':')
        plt.tight_layout(pad=1.5)

    plt.suptitle(u'鸢尾花数据SVM分类器不同C参数效果比较',fontsize=16)
    plt.show()


run()